package com.zebra.register;

import cn.hutool.core.util.RandomUtil;
import com.zebra.common.OnlineType;
import com.zebra.common.ServerBriefInfo;
import com.zebra.remoting.config.BasisCommandCode;
import com.zebra.remoting.config.EmptyMessage;
import com.zebra.remoting.config.GatewayServerInfo;
import com.zebra.remoting.config.TmsServerInfo;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.ZebraCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class LoadBalanceService {

    @Autowired
    private ServerRedisService serverRedisService;

    //-----获取-网关------
    public ServerBriefInfo loadGateway(){
        List<GatewayServerInfo> list = serverRedisService.findGwAll();
        if (null == list || list.isEmpty()){
            return null;
        }

        list = list.stream().filter(gw -> OnlineType.Online.value() == gw.getOnline()).collect(Collectors.toList());
        if (list.isEmpty()){
            return null;
        }

       return getBalanceGw(list).toServerBriefInfo();
    }


    /**
     * 获取 TMS 根据 cmd
     * @param cmd
     * @return
     */
    public TmsServerInfo loadTms(int cmd){
        List<TmsServerInfo> list = serverRedisService.findTmsAll();
        if (null == list || list.isEmpty()){
            return null;
        }
        String strCmd = cmd + ",";
        list = list.stream().filter(tms -> OnlineType.Online.value() == tms.getOnline() && tms.getCmds().contains(strCmd)).collect(Collectors.toList());
        if (list.isEmpty()){
            return null;
        }

       return getBalance(list);
    }


    public TmsServerInfo loadTms(int cmd, int gameId){
        List<TmsServerInfo> list = serverRedisService.findTmsAll();
        if (null == list || list.isEmpty()){
            return null;
        }
        String strCmd = cmd + ",";
        String strGameId = gameId + ",";
        list = list.stream().filter(tms -> OnlineType.Online.value() == tms.getOnline() && tms.getCmds().contains(strCmd) && tms.getGameIds().contains(strGameId)).collect(Collectors.toList());
        if (list.isEmpty()){
            return null;
        }

        return getBalance(list);

    }

    public TmsServerInfo getTmsBySid(int serverId){
        TmsServerInfo tmsServerInfo = serverRedisService.getTmsById(serverId);
        return null != tmsServerInfo && OnlineType.Online.value() == tmsServerInfo.getOnline() ? tmsServerInfo : null;
    }



    /**
     * 根据 权重 负载均衡
     * @param tmsList
     * @return
     */
    private TmsServerInfo  getBalance(List<TmsServerInfo> tmsList){
        if (tmsList.size() == 1){
            return tmsList.get(0);
        }
        List<Integer> ws = tmsList.stream().map(TmsServerInfo::getWeight).collect(Collectors.toList());
        int count = ws.stream().mapToInt(Integer::intValue).sum();
        int r = RandomUtil.randomInt(0, count+1);
        for (int i=0; i<ws.size(); i++){
            if (ws.get(i) >= r ){
                return tmsList.get(i);
            }
            r -= ws.get(i);
        }
        return tmsList.get(0);
    }


    private GatewayServerInfo  getBalanceGw(List<GatewayServerInfo> tmsList){
        if (tmsList.size() == 1){
            return tmsList.get(0);
        }
        List<Integer> ws = tmsList.stream().map(GatewayServerInfo::getWeight).collect(Collectors.toList());
        int count = ws.stream().mapToInt(Integer::intValue).sum();
        int r = RandomUtil.randomInt(0, count+1);
        for (int i=0; i<ws.size(); i++){
            if (ws.get(i) >= r ){
                return tmsList.get(i);
            }
            r -= ws.get(i);
        }
        return tmsList.get(0);
    }

    /**
     * 更改TMS 服务器的 在线状态 大厅不需要做因为，自由切换， 只有游戏服务
     * @param serverId
     * @param onlineType
     */
    public void updateTMSOnlineState(int serverId, int onlineType)throws Exception {
        TmsServerInfo tmsServerInfo = serverRedisService.getTmsById(serverId);
        if (null == tmsServerInfo){
            log.info("Server is null serverId: {}", serverId);
            throw new Exception("Server is null serverId: " + serverId);
        }
        if (tmsServerInfo.getOnline() == onlineType){
            log.info("TMS No need to change {} onlineType: {}", tmsServerInfo.toString(), onlineType);
            return;
        }

        Connection connection = RegisterConfigInfoManager.getInstance().getTmsConnection(serverId);
        if (null == connection || !connection.isFine()){
            log.info("Server connection not fine, sid:{}", serverId);
            throw new Exception("Server connection not fine, sid: " + serverId);
        }

        ZebraCommand remotingCommand = new ZebraCommand();
        remotingCommand.setCmd(BasisCommandCode.TMSOFFON.cmd());
        remotingCommand.setResponse(new EmptyMessage((byte) onlineType));
        connection.writeAndFlush(remotingCommand);

        tmsServerInfo.setOnline(onlineType);
        serverRedisService.updateTms(tmsServerInfo);

    }


    public List<TmsServerInfo> findTmsByAll(){
        return serverRedisService.findTmsAll();
    }

}
